#include "xtcpinterface.h"

#include "Interfaces/protocol.h"
#include "frameprocess.h"

#include <QDataStream>
#include <QHostAddress>
#include <QTcpSocket>
#include <QThread>

XTcpInterface::XTcpInterface()
{

}

bool XTcpInterface::connectToServer(QString ip, int port)
{
    if(m_socket == nullptr)
    {
        m_socket = new QTcpSocket();

        connect(m_socket, &QTcpSocket::readyRead, this, &XTcpInterface::parseServerData);
    }

    m_socket->connectToHost(QHostAddress(ip), port);
    bool ret = m_socket->waitForConnected(3000);
    return ret;
}

void XTcpInterface::registerUser(Core::User &user)
{
    PBS *pbs = serializeUserToPBS(user);
    pbs->MsgType = REGIST_REQUEST;

    sendDataToServer(pbs);

}

void XTcpInterface::updateUser(Core::User &user)
{
    PBS *pbs = serializeUserToPBS(user);
    pbs->MsgType = UPDATE_USER_REQUEST;

    sendDataToServer(pbs);
}

void XTcpInterface::login(Core::User &user)
{
    PBS *pbs = serializeUserToPBS(user);
    pbs->MsgType = LOGIN_REQUEST;

    sendDataToServer(pbs);
}

void XTcpInterface::logout(Core::User &user)
{
    PBS *pbs = serializeUserToPBS(user);
    pbs->MsgType = LOGOUT_REQUEST;

    sendDataToServer(pbs);
}

void XTcpInterface::addAnime(Core::Anime &anime)
{
    PBS *pbs = serializeAnimeToPBS(anime);
    pbs->MsgType = ADD_ANIME_REQUEST;

    sendDataToServer(pbs);
}

void XTcpInterface::deleteAnime(Core::Anime &anime)
{
    PBS *pbs = serializeAnimeToPBS(anime);
    pbs->MsgType = DELETE_ANIME_REQUEST;

    sendDataToServer(pbs);
}

void XTcpInterface::updateAnime(Core::Anime &anime)
{
    PBS *pbs = serializeAnimeToPBS(anime);
    pbs->MsgType = UPDATE_ANIME_REQUEST;

    sendDataToServer(pbs);
}

void XTcpInterface::getAnimeByName(QString name)
{

}

QList<Core::Anime> XTcpInterface::getAllAnimes()
{
    PBS *pbs = mkPBS(0);
    pbs->MsgType = GET_ALL_ANIMES_REQUEST;

    sendDataToServer(pbs);

    return  QList<Core::Anime>();
}

void XTcpInterface::browseByCategory(QString category)
{

}

QList<Core::Anime> XTcpInterface::browseByTag(Core::Filter &filter)
{
    this->filter = filter;
    PBS *pbs = serializeFilterToPBS(filter);
    pbs->MsgType = BROWSE_BY_TAG_REQUEST;

    sendDataToServer(pbs);
    return  QList<Core::Anime>();
}

void XTcpInterface::commentAnime(Core::Comment &comment)
{
    PBS *pbs = serializeCommentToPBS(comment);
    pbs->MsgType = COMMENT_ANIME_REQUEST;

    sendDataToServer(pbs);
}

void XTcpInterface::acceptComment(Core::Comment &comment)
{
    PBS *pbs = serializeCommentToPBS(comment);
    pbs->MsgType = ACCEPT_COMMENT_ANIME_REQUEST;

    sendDataToServer(pbs);
}

void XTcpInterface::rejectComment(Core::Comment &comment)
{
    PBS *pbs = serializeCommentToPBS(comment);
    pbs->MsgType = REJECT_COMMENT_ANIME_REQUEST;

    sendDataToServer(pbs);
}


QList<Core::Comment> XTcpInterface::getPendingComment()
{
    PBS *pbs = mkPBS(0);
    pbs->MsgType = GET_ALL_PENDING_COMMENTS_REQUEST;

    sendDataToServer(pbs);

    return QList<Core::Comment>();
}

void XTcpInterface::post(Core::Post &post)
{
    PBS *pbs = serializePostToPBS(post);
    pbs->MsgType = POST_REQUEST;

    sendDataToServer(pbs);
}

QList<Core::Post> XTcpInterface::getPosts(int cnt)
{
    PBS *pbs = mkPBS(0);
    pbs->MsgType = GET_POSTS_REQUEST;

    sendDataToServer(pbs);
    return QList<Core::Post>();
}

void XTcpInterface::acceptpost(Core::Post &post)
{
    PBS *pbs = serializePostToPBS(post);
    pbs->MsgType = ACCEPT_POST_REQUEST;

    sendDataToServer(pbs);
}

void XTcpInterface::rejectpost(Core::Post &post)
{
    PBS *pbs = serializePostToPBS(post);
    pbs->MsgType = REJECT_POST_REQUEST;

    sendDataToServer(pbs);
}

QList<Core::Post> XTcpInterface::getPendingPost()
{
    PBS *pbs = mkPBS(0);
    pbs->MsgType = GET_ALL_PENDING_POSTS_REQUEST;

    sendDataToServer(pbs);

    return QList<Core::Post>();
}

void XTcpInterface::postComment(Core::PostComment &comment)
{
    PBS *pbs = serializePostCommentToPBS(comment);
    pbs->MsgType = POST_COMMENT_REQUEST;

    sendDataToServer(pbs);
}

void XTcpInterface::likePost(Core::LikePost &likePost)
{
    PBS *pbs = serializeLikePostToPBS(likePost);
    pbs->MsgType = LIKE_POST_REQUEST;

    sendDataToServer(pbs);
}

bool XTcpInterface::sendPix(int postId)
{
    qint64 fileSize = m_pix_buf.size();
    if(fileSize > 0)
    {
        qDebug() << fileSize << "Org Pix Size;";
        qint64 bytesToSend = fileSize;
        const int chunkSize = 1024;
        int bytesSent = 0;
        while (bytesToSend > 0)
        {
            qint64 diffSize = qAbs(fileSize - bytesSent);
            bool isEnd = qAbs(fileSize - bytesSent) < chunkSize;
            QByteArray chunk = m_pix_buf.mid(bytesSent, isEnd ? int(diffSize) : chunkSize);

            Core::PixFromPost info;
            info.postId = postId;
            info.cell_pix_buf = chunk;

            PBS *pbs = serializePixFromPostToPBS(info);
            sendDataToServer(pbs);

            bytesToSend -= chunk.size();
            bytesSent += chunk.size();

            QThread::msleep(2);
        }
        return true;
    }
    return false;
}

void XTcpInterface::sendDataToServer(PBS *pbs)
{
    if (!pbs)
    {
        qCritical() << "PBS is null, cannot send!";
        return;
    }
    // 计算 PBS 的总大小
    int totalSize = pbs->PBSLen;

    // 将帧头和长度添加到数据流中
    QByteArray byteArray;
    QDataStream stream(&byteArray, QIODevice::WriteOnly);
    stream.setByteOrder(QDataStream::BigEndian); // 设置字节序（可选，使用大端序）

    // 写入 PBS 数据
    stream.writeRawData(reinterpret_cast<char*>(pbs), totalSize);

    // 加帧头帧尾
    QByteArray data = FrameProcess::addFrame(byteArray);

    // 发送数据
    qint64 bytesSent = m_socket->write(data);
    if (bytesSent == -1)
    {
        qCritical() << "Failed to send PBS data!";
    }
    else
    {
        qDebug() << "Sent" << bytesSent << "bytes of PBS data";
    }

    // 确保数据已经发送
    m_socket->flush();
    m_socket->waitForBytesWritten();
}

void XTcpInterface::parseServerData()
{
    // 从套接字中读取所有数据
    QByteArray data = m_socket->readAll();

    if (data.isEmpty())
    {
        qCritical() << "No data received from socket!";
        return;
    }

    QList<QByteArray> datas = FrameProcess::getDatas(data);


    for(auto &p : datas)
    {
        // 使用 QDataStream 解析数据
        QDataStream stream(p);
        stream.setByteOrder(QDataStream::BigEndian); // 假设使用大端序

        // 计算 PBS 数据大小
        uint PBSLen = 0;
        stream.readRawData((char*)&PBSLen, sizeof (uint));

        if(PBSLen != 0)
        {
            // 分配内存并读取 PBS 数据
            PBS* pbs = (PBS*)malloc(PBSLen);

            if (!pbs)
            {
                qCritical() << "Memory allocation failed for PBS!";
                return;
            }

            memset(pbs, 0, PBSLen); // 初始化 PBS 内存
            pbs->PBSLen = PBSLen;
            stream.readRawData((char*)(pbs ) + sizeof (uint), PBSLen - sizeof (uint));

            handlePBS(pbs);
        }
    }
}

void XTcpInterface::handlePBS(PBS *pbs)
{
    switch (pbs->MsgType)
    {
        case REGIST_RESPOND:
            {
                int code = pbs->Code;
                emit registerFinished(code);
                break;
            }
        case LOGIN_RESPOND:
            {
                int code = pbs->Code;
                if(code == NoError)
                {
                    Core::User user = deserializePBSToUser(pbs);
                    if(m_currentUser == nullptr)
                    {
                        m_currentUser = new Core::User;
                    }
                    *m_currentUser    = user;
                }

                emit loginFinished(code);
                break;
            }
        case LOGOUT_RESPOND:
            {
                int code = pbs->Code;

                emit logoutFinished(code);
                break;
            }
        case UPDATE_USER_RESPOND:
            {
                int code = pbs->Code;
                if(code == NoError)
                {
                    Core::User user = deserializePBSToUser(pbs);
                    if(m_currentUser == nullptr)
                    {
                        m_currentUser = new Core::User;
                    }
                    *m_currentUser    = user;
                }
                emit updateUserFinished(code);
                break;
            }
        case ADD_ANIME_RESPOND:
            {
                int code = pbs->Code;
                emit addAnimeFinished(code);
                getAllAnimes();
                break;
            }
        case DELETE_ANIME_RESPOND:
            {
                int code = pbs->Code;
                emit deleteAnimeFinished(code);
                getAllAnimes();
                break;
            }
        case UPDATE_ANIME_RESPOND:
            {
                int code = pbs->Code;
                emit updateAnimeFinished(code);
                getAllAnimes();
                break;
            }
        case GET_ANIME_BY_NAME_RESPOND:
            {
                int code = pbs->Code;
//        emit loginFinished(code);\
                break;
            }
        case GET_ALL_ANIMES_RESPOND:
            {
                int code = pbs->Code;
                QList<Core::Anime> animes = deserializePBSToAnims(pbs);
                emit getAllAnimeFinished(code, animes);

                browseByTag(this->filter);
                break;
            }
        case BROWSE_BY_CATEGORY_RESPOND:
            {
                int code = pbs->Code;


                break;
            }
        case BROWSE_BY_TAG_RESPOND:
            {
                int code = pbs->Code;
                QList<Core::Anime> animes = deserializePBSToAnims(pbs);
                emit getFilterAnimeFinished(code, animes);
                break;
            }
        case COMMENT_ANIME_RESPOND:
            {
                int code = pbs->Code;
                emit commentFinished(code);
                if(code == NoError)
                {
                    getPendingComment();
                }
                break;
            }
        case ACCEPT_COMMENT_ANIME_RESPOND:
            {
                int code = pbs->Code;
//        emit commentFinished(code);
                if(code == NoError)
                {
                    getPendingComment();
                    getAllAnimes();
                }
                break;
            }
        case REJECT_COMMENT_ANIME_RESPOND:
            {
                int code = pbs->Code;
//        emit commentFinished(code);
                if(code == NoError)
                {
                    getPendingComment();
                    getAllAnimes();
                }
                break;
            }
        case GET_ALL_PENDING_COMMENTS_RESPOND:
            {
                int code = pbs->Code;
                QList<Core::Comment> comments = deserializePBSToPostComments(pbs);
                emit getPendingCommentFinished(code, comments);
                break;
            }
        case POST_RESPOND:
            {
                int code = pbs->Code;
                emit postFinished(code);
                getPosts(10);
                break;
            }
        case GET_POSTS_RESPOND:
            {
                int code = pbs->Code;
                QList<Core::Post> posts = deserializePBSToPosts(pbs);;
                emit getAllPostsFinished(code, posts);
                qDebug() << "获取到帖子";
                break;
            }
        case ACCEPT_POST_RESPOND:
            {
                int code = pbs->Code;
                if(code == NoError)
                {
                    getPendingPost();
                    getPosts(10);
                }
                break;
            }
        case REJECT_POST_RESPOND:
            {
                int code = pbs->Code;
                if(code == NoError)
                {
                    getPendingPost();
                    getPosts(10);
                }
                break;
            }
        case GET_ALL_PENDING_POSTS_RESPOND:
            {
                int code = pbs->Code;
                QList<Core::Post> posts = deserializePBSToPosts(pbs);
                emit getPendingPostFinished(code, posts);



                static int cnt = 0;
                Core::PixFromPost info = deserializePBSToPixFromPost(pbs);
                m_pix_buf.append(info.cell_pix_buf);
                qDebug() << "cnt" << ++cnt << "buf size " << info.cell_pix_buf.size();
                if(info.cell_pix_buf.size() < 1024)
                {
                    info.cell_pix_buf = m_pix_buf;
                    m_pix_buf.clear();
                    cnt = 0;
                    emit sig_havePixPostShow(pbs->Code, info);
                }


                break;
            }
        case POST_COMMENT_RESPOND:
            {
                int code = pbs->Code;
                emit postCommentFinished(code);
                getPosts(10);
                break;
            }
        case LIKE_POST_RESPOND:
            {
                int code = pbs->Code;
                emit likePostFinished(code);
                getPosts(10);
                break;
            }
        case GET_POST_ID:
            {
                int code = pbs->Code;
                if(code != NoError)
                {
                    qDebug() << "code" << code;
                    return;
                }

                int postid = deserializePBSToQString(pbs).toInt();
                if(m_pix_buf.size() > 0)
                {
                    qDebug() << "send Pix:" << sendPix(postid);
                    m_pix_buf.clear();
                }
                break;
            }
        case PIX_FROM_POST_SEND:
            {
                static int cnt = 0;
                Core::PixFromPost info = deserializePBSToPixFromPost(pbs);
                m_pix_buf.append(info.cell_pix_buf);
                qDebug() << "cnt" << ++cnt << "buf size " << info.cell_pix_buf.size();
                if(info.cell_pix_buf.size() < 1024)
                {
                    info.cell_pix_buf = m_pix_buf;
                    m_pix_buf.clear();
                    cnt = 0;
                    emit sig_havePixPostShow(pbs->Code, info);
                }
                break;
            }
        case PIX_FROM_POST_RESPOND:
            {
                int code = pbs->Code;
                emit postFinished(code);
                break;
            }
    }
}
